package org.dreamwork.jasmine2.restful.client.gui.util;

import com.google.gson.Gson;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import org.dreamwork.gson.GsonHelper;

import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * Created by IntelliJ IDEA.
 * User: seth.yang
 * Date: 2014/12/9
 * Time: 14:56
 */
public class HttpUtil {
    private static ClientConnectionManager manager;
    private static HttpParams params = new BasicHttpParams ();

    private static final Logger logger = Logger.getLogger (HttpUtil.class);

    static {
        SchemeRegistry registry = new SchemeRegistry ();
        registry.register (new Scheme ("http", PlainSocketFactory.getSocketFactory (), 80));
        registry.register (new Scheme ("https", SSLSocketFactory.getSocketFactory (), 443));
        params = new BasicHttpParams ();
        params.setParameter (CoreConnectionPNames.CONNECTION_TIMEOUT, 60000);
        params.setParameter (CoreConnectionPNames.SO_TIMEOUT, 60000);
        HttpConnectionParams.setConnectionTimeout (params, 60000);
        HttpConnectionParams.setSoTimeout (params, 60000);
        manager = new ThreadSafeClientConnManager (params, registry);
    }

    public static String post (String url, Object body) throws ExecutionException, InterruptedException {
        Gson g = GsonHelper.getGson (true);
        return post (url, g.toJson (body));
    }

    public static String post (final String url, final String body) throws ExecutionException, InterruptedException {
        FutureTask<String> task = new FutureTask<String> (new Callable<String> () {
            @Override
            public String call () throws Exception {
                HttpPost post = new HttpPost (url);
                try {
                    post.setEntity (new StringEntity (body, "utf-8"));
                    HttpClient client = new DefaultHttpClient (manager, HttpUtil.params);
                    HttpResponse response = client.execute (post);
                    return EntityUtils.toString (response.getEntity (), "utf-8");
                } finally {
                    post.abort ();
                }
            }
        });
        new Thread (task).start ();
        return task.get ();
    }

    public static String get (String url) throws ExecutionException, InterruptedException {
        return get (url, null);
    }

    public static String get (final String url, final Map<String, Object> map) throws ExecutionException, InterruptedException {
        System.out.println ("[HTTP GET]: target = " + url);
        FutureTask<String> task = new FutureTask<String> (new Callable<String> () {
            @Override
            public String call () throws Exception {
                String uri = url;
                if (map != null && !map.isEmpty ()) {
                    StringBuilder builder = new StringBuilder ();
                    for (String name : map.keySet ()) {
                        if (builder.length () > 0) builder.append ('&');
                        Object value = map.get (name);
                        builder.append (name).append ('=')
                               .append (value == null ? "" : URLEncoder.encode (value.toString (), "utf-8"));
                    }
                    char c = url.indexOf ('?') < 0 ? '?' : '&';
                    uri = uri + c + builder;
                }
                HttpGet get = new HttpGet (uri);
                DefaultHttpRequestRetryHandler handler = new DefaultHttpRequestRetryHandler (3, false);
                try {
                    DefaultHttpClient client = new DefaultHttpClient (manager, HttpUtil.params);
                    client.setHttpRequestRetryHandler (handler);
                    HttpResponse response = client.execute (get);
                    if (logger.isDebugEnabled ()) {
                        logger.debug ("api response status: " + response.getStatusLine ().getStatusCode () + " " + response.getStatusLine ().getReasonPhrase ());
                    }
                    String content = EntityUtils.toString (response.getEntity (), "utf-8");
                    if (logger.isDebugEnabled ()) {
                        logger.debug ("api response body: " + content);
                    }
                    return content;
                } finally {
                    get.abort ();
                }
            }
        });
        new Thread (task).start ();
        return task.get ();
    }
}